package com.ocm.tourism.core.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.RowMapperResultSetExtractor;
import org.springframework.jdbc.core.SqlProvider;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;

public class QueryStatementCallback<T> implements StatementCallback<T>, SqlProvider {

   private String sql;

   private int firstResult;

   private int maxRows;

   private RowMapper<?> rowMapper;

   private NativeJdbcExtractor nativeJdbcExtractor; 

   @SuppressWarnings({ "unchecked", "rawtypes" })
   public T doInStatement(Statement stmt) throws SQLException, DataAccessException {
      ResultSet rs = null;
      try {
         applyStatementSettings(stmt);
         rs = stmt.executeQuery(sql);
         ResultSet rsToUse = rs;
         if (nativeJdbcExtractor != null) {
            rs.absolute(firstResult);
            rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
         }
         ResultSetExtractor rse = getRowMapperResultSetExtractor(rowMapper);
         return (T) rse.extractData(rsToUse);
      } finally {
         JdbcUtils.closeResultSet(rs);
      }
   }

   @SuppressWarnings({ "rawtypes", "unchecked" })
   public RowMapperResultSetExtractor getRowMapperResultSetExtractor(RowMapper rowMapper){
      return new RowMapperResultSetExtractor(rowMapper);
   }

   protected void applyStatementSettings(Statement stmt) throws SQLException {
      int maxRows = getMaxRows();
      if (maxRows > 0) {
         stmt.setMaxRows(maxRows);
      }
   }

   public int getFirstResult() {
      return this.firstResult;
   }

   public void setFirstResult(int firstResult) {
      this.firstResult = firstResult;
   }

   public int getMaxRows() {
      return maxRows;
   }

   public void setMaxRows(int maxRows) {
      this.maxRows = maxRows;
   }

   public void setSql(String sql) {
      this.sql = sql;
   }

   public String getSql() {
      return this.sql;
   }

   @SuppressWarnings("rawtypes")
   public RowMapper getRowMapper() {
      return rowMapper;
   }

   public <E> void setRowMapper(RowMapper<E> rowMapper) {
      this.rowMapper = rowMapper;
   }

   public NativeJdbcExtractor getNativeJdbcExtractor() {
      return nativeJdbcExtractor;
   }

   public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
      this.nativeJdbcExtractor = nativeJdbcExtractor;
   }
}
